/-
Test that try? runs user suggestion tactics in parallel via attempt_all_par.

This test uses IO.stdGenRef (a builtin_initialize ref) to demonstrate parallelism:
- Tactic 1 (high prio): waits 1000ms, then checks if the random seed was changed
- Tactic 2 (low prio): immediately sets the seed to a magic value, then succeeds

If sequential: Tactic 1 executes first, waits, seed unchanged, fails.
              Then tactic 2 executes, sets seed, succeeds. Only one suggestion.
If parallel: Both tactics start together. Tactic 2 sets seed immediately.
            Tactic 1 waits 1000ms, sees changed seed, succeeds. Two suggestions.
-/
module
public import Lean
public meta import Lean.Elab.Tactic.Try

open Lean Meta Elab Tactic Try

-- An opaque goal that built-in tactics (including solve_by_elim) won't solve
opaque ParallelTestGoal : Prop
axiom parallelTestGoalHolds : ParallelTestGoal

-- Magic seed value to signal parallelism
meta def magicSeed : Nat := 314159265

-- Tactic that waits, then checks if seed was changed
elab "wait_and_check_seed" : tactic => do
  IO.sleep 1000
  let gen ← IO.stdGenRef.get
  let expected := mkStdGen magicSeed
  if gen.s1 == expected.s1 && gen.s2 == expected.s2 then
    evalTactic (← `(tactic| exact parallelTestGoalHolds))
  else
    throwError "seed not changed (sequential execution detected)"

-- Tactic that immediately sets seed and succeeds
elab "set_seed_and_succeed" : tactic => do
  IO.setRandSeed magicSeed
  evalTactic (← `(tactic| exact parallelTestGoalHolds))

-- Register both tactics as user suggestions
-- High priority tactic: reset seed first (to ensure clean state), then return waiting tactic
@[local try_suggestion 900]
meta def waitAndCheckSolver (_goal : MVarId) (_info : Try.Info) : MetaM (Array (TSyntax `tactic)) := do
  -- Reset to a different seed to ensure we're testing actual communication
  IO.setRandSeed 0
  return #[← `(tactic| wait_and_check_seed)]

-- Low priority tactic returns the seed-setting tactic
@[local try_suggestion 800]
meta def setFlagSolver (_goal : MVarId) (_info : Try.Info) : MetaM (Array (TSyntax `tactic)) := do
  return #[← `(tactic| set_seed_and_succeed)]

-- If parallel: both tactics succeed (tactic 1 sees seed change after waiting)
-- If sequential: only tactic 2 succeeds (tactic 1 sees unchanged seed)
--
-- EXPECTED ON MASTER (sequential): Only one suggestion
-- EXPECTED ON try_par (parallel): Two suggestions
/--
info: Try these:
  [apply] wait_and_check_seed
  [apply] set_seed_and_succeed
-/
#guard_msgs in
example : ParallelTestGoal := by
  try?
